<script setup lang="ts">
import {
  computed,
  defineModel,
  inject,
  onBeforeUnmount,
  onMounted,
  PropType,
  Ref,
  ref,
} from 'vue'
import { translate } from '../../../i18n'
import StatIcon from '../../../components/StatIcon.vue'
import { RankInfo } from '../../../types/starrail/srRankMap'
import {
  AttributeInfo,
  CharacterInfo,
  RelicSetInfo,
} from '../../../types/starrail/srPlayerInfo'
import { useDialog } from '../../../utils/template-dialog'
import SRCharDetailsDialog from './SRCharDetailsDialog.vue'
import MyTag from '../../../components/MyTag.vue'
import ScrollWrapper from '../../../components/ScrollWrapper.vue'
import MyTooltip from '../../../components/MyTooltip.vue'
import MyCarousel from '../../../components/MyCarousel.vue'
import CustomUIDInput from '../../../components/CustomUIDInput.vue'
import GamepadIcon from '../../../components/GamepadIcon.vue'
import { useStore } from '../../../store'

// import rankMap from '../textMaps/character_ranks.json' with { type: 'json' }

const gamepadMode = defineModel({
  type: String as PropType<
    | 'main'
    | 'settings'
    | 'window-action'
    | 'gs-player'
    | 'sr-player'
    | 'dialog'
    | 'out'
  >,
  required: false,
})

const apiUrl = 'https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/'
const store = useStore()

const playerInfo = ref(store.game.sr.playerInfo)
const playerInfoLoading = ref(false)
const playerInfoFailed = ref(false)
const uidInput = ref('')
const uidInputDom = ref()
let uid = ''
const charsPage = ref(0)
const pages = computed(() =>
  playerInfo.value &&
  playerInfo.value.characters &&
  playerInfo.value.characters.length > 10
    ? Math.floor((playerInfo.value.characters.length - 10) / 6 - 0.1) + 1
    : 0,
)
const hScale = inject<Ref<number>>('hScale')
const vScale = inject<Ref<number>>('vScale')
const gpType = inject<Ref<string>>('gpType')

const charsScrollbar = ref()
const cardsCarouselRef = ref()
const showcaseIdx = ref(0)
const relicIdx = ref(0)
const ascLevelMap = [20, 30, 40, 50, 60, 70, 80]
let rankMap: Record<string, RankInfo> = {}
const ranksReady = ref(false)
const initReady = ref(false)

const rAF = window.requestAnimationFrame
let rAFId: number | null = null

let inThrottle = false
const gameLoop = () => {
  const gamepads = navigator.getGamepads()
  let gp: Gamepad | null = null

  for (let i = 0; i < gamepads.length; i++) {
    if (gamepads[i]) {
      gp = gamepads[i]
      break
    }
  }

  if (!gp) {
    return
  }
  if (!document.hasFocus()) {
    rAF(gameLoop)
    return
  }

  // A: Request user info
  if (gamepadMode.value === 'sr-player' && gp.buttons[0].pressed) {
    if (!inThrottle) {
      inThrottle = true
      requestInfo()
      setTimeout(() => {
        inThrottle = false
      }, 300)
    }
  }

  // Y: Focus on CustomUIDInput's input
  if (gamepadMode.value === 'sr-player' && gp.buttons[3].pressed) {
    if (!inThrottle) {
      inThrottle = true
      uidInputDom.value?.focusInput()
      setTimeout(() => {
        inThrottle = false
      }, 300)
    }
  }

  // X: Open details dialog
  if (
    gamepadMode.value === 'sr-player' &&
    gp.buttons[2].pressed &&
    playerInfo
  ) {
    if (!inThrottle) {
      inThrottle = true
      showCharDetails(showcaseIdx.value)
      setTimeout(() => {
        inThrottle = false
      }, 300)
    }
  }

  // LS: Select character
  if (gamepadMode.value === 'sr-player' && gp.axes[0] < -0.9 && playerInfo) {
    if (!inThrottle) {
      inThrottle = true
      if (showcaseIdx.value > 0) {
        setShowcase(showcaseIdx.value - 1)
      }
      setTimeout(() => {
        inThrottle = false
      }, 150)
    }
  }
  if (gamepadMode.value === 'sr-player' && gp.axes[0] > 0.9 && playerInfo) {
    if (!inThrottle) {
      inThrottle = true
      if (showcaseIdx.value < playerInfo.value.characters.length - 1) {
        setShowcase(showcaseIdx.value + 1)
      }
      setTimeout(() => {
        inThrottle = false
      }, 150)
    }
  }

  // RS: Select Relics
  if (gamepadMode.value === 'sr-player' && gp.axes[2] < -0.9 && playerInfo) {
    if (!inThrottle) {
      inThrottle = true
      if (relicIdx.value == 0) {
        relicIdx.value =
          playerInfo.value.characters[showcaseIdx.value].relics.length - 1
      } else {
        relicIdx.value--
      }
      setTimeout(() => {
        inThrottle = false
      }, 150)
    }
  }
  if (gamepadMode.value === 'sr-player' && gp.axes[2] > 0.9 && playerInfo) {
    if (!inThrottle) {
      inThrottle = true
      if (
        relicIdx.value ==
        playerInfo.value.characters[showcaseIdx.value].relics.length - 1
      ) {
        relicIdx.value = 0
      } else {
        relicIdx.value++
      }
      setTimeout(() => {
        inThrottle = false
      }, 150)
    }
  }

  if (rAFId) {
    rAFId = rAF(gameLoop)
  }
}

onMounted(() => {
  fetch(translate('sr_charRanksJsonUrl'))
    .then(response => response.json())
    .then(resp => {
      rankMap = resp
      ranksReady.value = true
    })
    .catch(error => {
      console.error('Error loading JSON:', error)
    })

  if (playerInfo.value) {
    uid = playerInfo.value.player.uid
    uidInput.value = uid
  }
  initReady.value = true

  if (gamepadMode.value) {
    rAFId = rAF(gameLoop)
  }
})

const mergeToPlayerinfo = (newArr: CharacterInfo[]) => {
  if (!playerInfo.value) {
    return
  }

  for (let i = newArr.length - 1; i >= 0; i--) {
    let newChar = newArr[i]
    let exists = false
    // for (let j = playerInfo.value.characters.length - 1; j >= 0; j--) {
    for (let j = 0; j < playerInfo.value.characters.length; j++) {
      let oldChar = playerInfo.value.characters[j]
      if (oldChar.id == newChar.id) {
        playerInfo.value.characters[j] = newChar
        exists = true
        break
      }
    }
    if (!exists) {
      playerInfo.value.characters.push(newChar)
    }
  }
}

onBeforeUnmount(() => {
  rAFId = null
})

const requestInfo = () => {
  uid = uidInput.value
  playerInfoFailed.value = false
  window.axios
    .get(translate('sr_playerInfoUrl', { uid: uid }))
    .then(resp => {
      console.log(playerInfo)
      console.log(resp.player.uid)
      if (playerInfo.value && playerInfo.value.player.uid == resp.player.uid) {
        console.log('uid equal')
        mergeToPlayerinfo(resp.characters)
        playerInfo.value.player = resp.player
      } else {
        console.log('uid not equal')
        playerInfo.value = resp
      }

      if (!playerInfo.value) {
        playerInfoLoading.value = false
        return
      }

      playerInfo.value.characters.sort(function (
        a: CharacterInfo,
        b: CharacterInfo,
      ) {
        // 等级
        if (a.level < b.level) {
          return 1
        } else if (a.level > b.level) {
          return -1
        } else {
          // 突破等级
          if (a.promotion < b.promotion) {
            return 1
          } else if (a.promotion > b.promotion) {
            return -1
          } else {
            // 行迹总等级
            if (totalSkillLvs(a) < totalSkillLvs(b)) {
              return 1
            } else {
              return -1
            }
          }
          //     // 双爆分
          //     const critA = a.stats.critRate.value * 200 + a.stats.critDamage.value * 100
          //     const critB = b.stats.critRate.value * 200 + b.stats.critDamage.value * 100
          //     if (critA < critB) {
          //         return 1
          //     } else {
          //         return -1
          //     }
          // }
        }
      })

      store.game.sr.playerInfo = playerInfo.value
      playerInfoLoading.value = false
    })
    .catch(err => {
      console.error(err)
      playerInfoLoading.value = false
      playerInfoFailed.value = true
    })
  playerInfoLoading.value = true
  console.log(uid)
}

const totalSkillLvs = (c: CharacterInfo) => {
  let res = 0
  for (const skill of c.skill_trees) {
    res += skill.level
  }
  return res
}

const setShowcase = (index: number) => {
  relicIdx.value = 0
  charsPage.value = Math.floor(index / 10)
  charsScrollbar.value.scrollTo({
    left: charsPage.value * 48 * 6,
    top: 0,
    behavior: 'smooth',
  })
  cardsCarouselRef.value?.setPane?.(index)
  showcaseIdx.value = index
}

const charsPageNext = () => {
  if (charsPage.value < pages.value) {
    charsPage.value++
    charsScrollbar.value.scrollTo({
      // about 48 for each icon, 8 icons on each page
      left: charsPage.value * 48 * 6,
      top: 0,
      behavior: 'smooth',
    })
  }
}
const charsPagePrev = () => {
  if (charsPage.value > 0) {
    charsPage.value--
    charsScrollbar.value.scrollTo({
      left: charsPage.value * 48 * 6,
      top: 0,
      behavior: 'smooth',
    })
  }
}

const findField = (range: AttributeInfo[], field: string) => {
  for (let i = 0; i < range.length; i++) {
    const element = range[i]
    if (element.field === field) {
      return element
    }
  }
  return {
    field: '',
    name: '',
    icon: '',
    value: 0,
    display: '',
    percent: false,
  }
}

const parseRankDesc = (str: string) => {
  return str.replace('\\n', '\n')
}

const getOuterSets = (sets: RelicSetInfo[]) => {
  if (sets.length == 0) {
    return translate('sr_noRelicSets')
  } else if (sets.length == 1) {
    return sets[0].id[0] == '3'
      ? translate('sr_noRelicSets')
      : sets[0].name + ' 2'
  } else {
    if (sets[1].id[0] == '3') {
      return sets[0].name + ' 2'
    } else if (sets[1].num == 2) {
      return sets[0].name + ' 2\n' + sets[1].name + ' 2'
    } else {
      return sets[0].name + ' 4'
    }
  }
}
const getInnerSet = (sets: RelicSetInfo[]) => {
  if (sets.length > 0 && sets[sets.length - 1].id[0] == '3') {
    return sets[sets.length - 1].name
  } else {
    return translate('sr_noRelicSets')
  }
}

const showCharDetails = (index: number) => {
  if (gamepadMode.value) {
    gamepadMode.value = 'dialog'
    rAFId = null
  }
  if (!playerInfo.value) {
    return
  }

  useDialog(
    SRCharDetailsDialog,
    {
      onCancel: gamepadMode.value
        ? (dispose: () => void) => {
            gamepadMode.value = 'sr-player'
            rAFId = rAF(gameLoop)
            dispose()
          }
        : undefined,
    },
    {
      title:
        playerInfo.value.characters[index].name +
        ' ' +
        translate('sr_charDetails'),
      character: playerInfo.value.characters[index],
      showOk: false,
      hScale: hScale,
      vScale: vScale,
      gamepadMode: !!gamepadMode.value,
      gpType: gpType?.value,
    },
  )
}
</script>

<template>
  <div
    class="bg-white dark:bg-[#222] mb-3 transition-all"
    :class="{ loading: !initReady }"
    style="border-radius: 4.5vh 4.5vh 30px 30px"
  >
    <!-- HEADER -->
    <div
      class="flex flex-row w-full p-0 relative justify-between z-50"
      style="height: 9vh"
    >
      <!-- 右上角加载提示 / 报错提示 -->
      <div
        v-if="playerInfoLoading"
        class="absolute top-0 right-0 bottom-0 z-0"
        style="margin-left: 1vw; right: 2vw; top: 3vh"
        :style="`font-size: calc(max(14px * min(${hScale}, ${vScale}), 16px))`"
      >
        {{ $t('sr_loadingPlayerInfo') }}
      </div>
      <div
        v-if="playerInfoFailed"
        class="absolute bottom-0 z-0 text-red-500"
        style="margin-left: 1vw; right: 2vw; top: 3vh"
        :style="`font-size: calc(max(14px * min(${hScale}, ${vScale}), 16px))`"
      >
        {{ $t('sr_playerInfoFailed') }}
      </div>
      <!-- 左上角头像、昵称 -->
      <div
        v-if="playerInfo"
        class="flex flex-row content-start items-center"
        style="width: 35vw"
      >
        <img
          class="rounded-full bg-slate-200"
          :style="`height: 6vh; margin-left: 1.5vh`"
          :src="
            playerInfo.player.avatar
              ? apiUrl + playerInfo.player.avatar.icon
              : ''
          "
        />
        <div
          class="font-sr"
          style="margin-left: 1.5vh"
          :style="`font-size: calc(max(16px * min(${hScale}, ${vScale}), 20px))`"
        >
          {{ playerInfo.player.nickname }}
        </div>
      </div>
      <div v-else style="width: 35vw" />
      <div class="flex flex-row">
        <CustomUIDInput
          ref="uidInputDom"
          v-model="uidInput"
          @submit="requestInfo"
          :gamepad-mode="!!gamepadMode"
          style="margin-top: 2vh; margin-bottom: 1.5vh; z-index: 10"
          :style="`font-size: calc(max(14px * min(${hScale}, ${vScale}), 16px))`"
        />
      </div>
      <!-- 右侧 WL AR -->
      <div
        v-if="playerInfo && !playerInfoLoading && !playerInfoFailed"
        style="width: 35vw; position: relative"
      >
        <div
          class="h-full flex flex-row justify-end items-center"
          :style="`font-size: calc(16px * min(${hScale}, ${vScale}))`"
        >
          <MyTag class="mx-2">
            <div class="flex flex-row">
              {{ $t('sr_eqLv') }}
              <span
                class="font-sr-sans"
                style="margin-left: 1ch"
                :style="`margin-top: calc(1px * min(${hScale}, ${vScale}))`"
              >
                {{ playerInfo.player.world_level }}
              </span>
            </div>
          </MyTag>
          <MyTag class="mr-4">
            <div class="flex flex-row">
              {{ $t('sr_playerLv') }}
              <span
                class="font-sr-sans"
                style="margin-left: 1ch"
                :style="`margin-top: calc(1px * min(${hScale}, ${vScale}))`"
              >
                {{ playerInfo.player.level }}
              </span>
            </div>
          </MyTag>
        </div>
      </div>
      <div v-else style="width: 35vw" />
    </div>
    <!-- BODY -->
    <div v-if="playerInfo && playerInfo.characters.length > 0" class="relative">
      <!-- 角色头像列表 10人一页 -->
      <div class="flex flex-row w-full justify-center absolute z-10 top-0">
        <div
          class="flex flex-row justify-between"
          style="width: 690px; transform-origin: center top"
          :style="`transform: scale(${gamepadMode ? `min(${hScale}, ${vScale})` : hScale})`"
        >
          <div class="relative z-50" style="width: 15%">
            <div
              class="absolute right-2 top-3 rounded-full w-9 h-9 pt-1 bg-white hover:bg-gray-200 active:-translate-x-1 transition-all bg-opacity-80 dark:bg-black dark:hover:bg-gray-700 dark:bg-opacity-80"
              @click="charsPagePrev"
              :class="charsPage == 0 ? 'disabled' : ''"
            >
              <i class="bi bi-chevron-left text-lg text-center" />
            </div>
          </div>
          <ScrollWrapper
            ref="charsScrollbar"
            no-resize
            show-bar="never"
            width="auto"
            style="max-width: 70%"
          >
            <div class="flex flex-row flex-nowrap w-max">
              <div
                v-for="(character, index) in playerInfo.characters"
                :key="index"
                class="relative w-12 h-12 z-50"
                @click="setShowcase(index)"
              >
                <div
                  class="absolute bottom-0 w-9 h-9 border-2 rounded-full bg-white transition-all dark:border-2 dark:border-gray-500 dark:bg-[#222]"
                  :class="{
                    'border-blue-600 border-3 dark:border-3 dark:border-blue-500 dark:bg-gray-500':
                      showcaseIdx == index,
                  }"
                  style="left: 10px"
                ></div>
                <img
                  class="absolute bottom-0 char-side-icon rounded-full ml-2 w-9 h-9 hover:transform hover:scale-110 hover:-translate-y-1 active:scale-100 active:translate-y-0 transition-all object-cover"
                  :src="apiUrl + character.icon"
                />
              </div>
            </div>
          </ScrollWrapper>
          <div class="relative z-50" style="width: 15%">
            <div
              class="absolute left-2 top-3 rounded-full w-9 h-9 pt-1 bg-white hover:bg-gray-200 active:translate-x-1 transition-all bg-opacity-80"
              @click="charsPageNext"
              :class="charsPage == pages ? 'disabled' : ''"
            >
              <i class="bi bi-chevron-right text-lg text-center" />
            </div>
          </div>
        </div>
      </div>

      <!-- 角色详情卡片 -->
      <div
        :style="`height: calc(616px * ${gamepadMode ? `calc(min(${hScale}, ${vScale}) / 616 * 556)` : hScale})`"
      />
      <MyCarousel
        ref="cardsCarouselRef"
        class="gacha-mask absolute z-0 left-0 top-0"
        :autoplay="false"
        show-arrow="never"
        animation="fade-swipe"
        style="width: 984px; height: 616px; transform-origin: left top"
        :style="`transform: scale(${gamepadMode ? `calc(min(${hScale}, ${vScale}) / 616 * 556)` : hScale});
          border-radius: calc(30px / ${gamepadMode ? `calc(min(${hScale}, ${vScale}) / 616 * 556)` : hScale})`"
      >
        <div
          v-for="(character, index) in playerInfo.characters"
          :key="index"
          class="z-0 relative w-full mt-12"
        >
          <div
            class="mt-4 w-full absolute top-0 left-0 right-0 transition-all"
            style="transition-duration: 300ms"
          >
            <!-- absolute： 卡片元素背景、元素图标 -->
            <img
              class="relative z-0 w-full"
              src="../../../assets/srBg.jpg"
              :style="`border-radius: calc(30px / ${gamepadMode ? `min(${hScale}, ${vScale})` : hScale}`"
            />
            <img
              class="h-1/4 absolute opacity-50"
              :src="character.element ? apiUrl + character.element.icon : ''"
              style="top: -7px; right: -18px"
            />
            <!-- 卡片前景 -->
            <div
              class="flex flex-row h-full absolute top-0 left-0 right-0 bottom-0 z-10"
            >
              <!-- 立绘 -->
              <div
                class="left-gacha w-7/12 absolute left-0 bottom-0 z-10"
                style="height: 117%"
              >
                <img
                  class="inline-block object-cover bottom-0 left-0 absolute z-10"
                  style="height: 100%"
                  :src="apiUrl + character.portrait"
                />
              </div>
              <!-- 左上角命途、等级 -->
              <div
                class="absolute top-2 left-2 z-50 rounded-full backdrop-blur-lg bg-opacity-25 bg-black h-12"
              >
                <div class="ml-3" style="margin-top: 10px">
                  <img
                    class="inline h-6 mb-2"
                    :src="character.path ? apiUrl + character.path.icon : ''"
                  />
                  <span class="text-gray-200 font-sr-sans text-xl">
                    Lv. {{ character.level }} /
                  </span>
                  <span class="text-gray-400 text-lg mr-4 font-sr-sans">
                    {{ ascLevelMap[character.promotion] }}
                  </span>
                </div>
              </div>
              <!-- 左下角星魂 -->
              <div class="absolute bottom-2 left-2 z-50">
                <div class="flex flex-col">
                  <div class="flex flex-row relative">
                    <MyTooltip v-for="idx in 6" :key="idx" placement="top">
                      <template #content>
                        <div class="max-w-lg" v-if="ranksReady">
                          <div class="font-sr text-xl">
                            {{
                              rankMap[character.id + '0' + idx.toString()].name
                            }}
                            <span
                              v-if="idx > character.rank"
                              class="ml-1 text-base text-gray-200"
                              >{{ $t('sr_lockedRank') }}</span
                            >
                          </div>
                          <div
                            class="font-sr-sans text-sm mt-1 whitespace-pre-wrap"
                          >
                            {{
                              parseRankDesc(
                                rankMap[character.id + '0' + idx.toString()]
                                  .desc,
                              )
                            }}
                          </div>
                        </div>
                      </template>
                      <div v-if="idx <= character.rank" class="relative">
                        <div
                          class="absolute bottom-0 left-2 w-8 h-8 rounded-full bg-black z-20 opacity-70"
                        ></div>
                        <img
                          class="relative h-8 rounded-full ml-2 z-30"
                          :src="apiUrl + character.rank_icons[idx - 1]"
                        />
                      </div>
                      <div v-else>
                        <img
                          src="../../../assets/locked.png"
                          class="w-8 opacity-70 ml-2 bg-black rounded-full"
                        />
                      </div>
                    </MyTooltip>
                  </div>
                </div>
              </div>
              <!-- 右侧详情 -->
              <div
                class="w-1/2 h-full absolute top-6 right-6 bottom-4 flex flex-col z-20"
              >
                <!-- 角色名字 -->
                <div class="w-full text-right">
                  <span
                    class="text-white"
                    style="font-size: 2.15rem; line-height: 2.5rem"
                    :class="
                      $t('sr_displayCompactFont') === 'true'
                        ? 'font-sr-sans'
                        : 'font-sr'
                    "
                    >{{ character.name }}</span
                  >
                </div>
                <!-- 右侧第一块：属性 -->
                <div
                  class="mt-2 text-gray-200 text-xl text-left w-full rounded-xl px-2 py-3 pl-4 bg-black bg-opacity-20 backdrop-blur-md grid grid-cols-4 grid-rows-2"
                >
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="hp"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3">{{
                      Math.floor(character.attributes[0].value) +
                      Math.floor(findField(character.additions, 'hp').value)
                    }}</span>
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="atk"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3">{{
                      Math.floor(character.attributes[1].value) +
                      Math.floor(findField(character.additions, 'atk').value)
                    }}</span>
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="def"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3">{{
                      Math.floor(character.attributes[2].value) +
                      Math.floor(findField(character.additions, 'def').value)
                    }}</span>
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="effect_res"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3"
                      >{{
                        (
                          findField(character.additions, 'effect_res').value *
                          100
                        ).toFixed(1)
                      }}%</span
                    >
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="spd"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3">{{
                      (
                        character.attributes[3].value +
                        findField(character.additions, 'spd').value
                      ).toFixed(0)
                    }}</span>
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="crit_rate"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3"
                      >{{
                        (
                          (character.attributes[4].value +
                            findField(character.additions, 'crit_rate').value) *
                          100
                        ).toFixed(1)
                      }}%</span
                    >
                  </div>
                  <div class="w-full flex flex-row">
                    <StatIcon
                      game="sr"
                      stat="crit_dmg"
                      fill="#d1d5db"
                      class="h-5 w-5"
                      style="margin-top: 3px"
                    />
                    <span class="text-gray-200 text-right font-sr-sans ml-3"
                      >{{
                        (
                          (character.attributes[5].value +
                            findField(character.additions, 'crit_dmg').value) *
                          100
                        ).toFixed(1)
                      }}%</span
                    >
                  </div>
                  <div
                    class="mr-2 rounded-full text-sm bg-white bg-opacity-20 text-center hover:bg-opacity-30 active:scale-95 active:bg-opacity-40 cursor-default transition-all"
                    @click="showCharDetails(index)"
                  >
                    <div class="font-sr-sans flex flex-row justify-center">
                      <GamepadIcon
                        icon="X"
                        v-if="gamepadMode"
                        class="h-[20px] mt-1 bg-gray-900 rounded-full mr-1"
                      />
                      <div class="mt-[5px]">{{ $t('sr_details') }}</div>
                    </div>
                  </div>
                </div>
                <!-- 右侧第二块：光锥 -->
                <div
                  v-if="character.light_cone"
                  class="mt-2 w-full rounded-xl flex flex-row bg-black bg-opacity-20 backdrop-blur-md"
                  style="height: 90px"
                >
                  <img
                    class="object-cover w-44 h-full"
                    :src="apiUrl + character.light_cone.preview"
                  />
                  <div class="w-full h-full relative">
                    <div class="flex flex-row justify-between ml-2 mt-5">
                      <div
                        class="truncated text-gray-200 text-2xl text-left font-sr-sans"
                        :class="
                          $t('sr_displayCompactFont') === 'true'
                            ? 'font-sr-sans'
                            : 'font-sr'
                        "
                        style="width: 340px"
                      >
                        {{
                          character.light_cone ? character.light_cone.name : ''
                        }}
                      </div>
                      <div
                        class="text-gray-300 mr-2 text-sm absolute right-0 top-0"
                      >
                        {{ $t('sr_superimposition') }}
                        <span class="text-gray-100 font-sr-sans text-base">{{
                          character.light_cone ? character.light_cone.rank : ''
                        }}</span>
                      </div>
                      <div
                        class="absolute right-1 bottom-1 px-2 rounded-full font-sr-sans bg-opacity-20 bg-white"
                      >
                        <span class="text-gray-200 text-xl"
                          >{{
                            character.light_cone
                              ? character.light_cone.level
                              : ''
                          }}
                          /</span
                        >
                        <span class="text-gray-400 ml-1">{{
                          ascLevelMap[
                            character.light_cone
                              ? character.light_cone.promotion
                              : 0
                          ]
                        }}</span>
                      </div>
                    </div>
                    <div
                      class="text-gray-300 ml-2 text-left grid grid-cols-4 mt-1"
                    >
                      <div class="flex flex-row">
                        <StatIcon
                          game="sr"
                          :stat="character.light_cone.attributes[0].field"
                          fill="#d1d5db"
                          class="h-5 w-5 mr-2"
                          style="margin-top: 3px"
                        />
                        <span class="text-gray-200 font-sr-sans text-lg">{{
                          character.light_cone
                            ? character.light_cone.attributes[0].display
                            : '-'
                        }}</span>
                      </div>
                      <div class="flex flex-row">
                        <StatIcon
                          game="sr"
                          :stat="character.light_cone.attributes[1].field"
                          fill="#d1d5db"
                          class="h-5 w-5 mr-2"
                          style="margin-top: 3px"
                        />
                        <span class="text-gray-200 font-sr-sans text-lg">{{
                          character.light_cone
                            ? character.light_cone.attributes[1].display
                            : '-'
                        }}</span>
                      </div>
                      <div class="flex flex-row">
                        <StatIcon
                          game="sr"
                          :stat="character.light_cone.attributes[2].field"
                          fill="#d1d5db"
                          class="h-5 w-5 mr-2"
                          style="margin-top: 3px"
                        />
                        <span class="text-gray-200 font-sr-sans text-lg">{{
                          character.light_cone
                            ? character.light_cone.attributes[2].display
                            : '-'
                        }}</span>
                      </div>
                    </div>
                  </div>
                </div>
                <div
                  v-else
                  class="mt-2 pt-7 w-full rounded-xl text-center text-gray-300 bg-black bg-opacity-20 backdrop-blur-md"
                  style="height: 90px"
                >
                  {{ $t('sr_noLightcone') }}
                </div>
                <!-- 右侧第三块：行迹 -->
                <div
                  class="mt-2 px-2 py-3 w-full rounded-xl bg-black bg-opacity-20 backdrop-blur-md grid grid-cols-4 grid-rows-1 relative z-50"
                >
                  <div
                    v-for="idx in 4"
                    :key="idx"
                    class="h-full flex flex-row cursor-default"
                  >
                    <MyTooltip placement="left" max-width="500px" middle>
                      <template #content>
                        <div class="max-w-md">
                          <div class="font-sr text-xl">
                            {{ character.skills[idx - 1].name }}
                          </div>
                          <div class="font-sr-sans text-sm mt-1">
                            {{
                              character.skills[idx - 1].simple_desc
                                ? character.skills[idx - 1].simple_desc
                                : character.skills[idx - 1].desc
                            }}
                          </div>
                        </div>
                      </template>
                      <div
                        class="h-12 w-12 p-1 rounded-full border-2"
                        :style="`border-color: ${character.element ? character.element.color : 'white'}`"
                      >
                        <img :src="apiUrl + character.skills[idx - 1].icon" />
                      </div>
                    </MyTooltip>
                    <div
                      v-if="
                        character.skill_trees[idx - 1].level >=
                        character.skill_trees[idx - 1].max_level
                      "
                      class="ml-2 mt-2 text-orange-300 text-xl align-middle h-full font-sr-sans"
                    >
                      MAX
                    </div>
                    <div
                      v-else
                      class="ml-2 mt-2 text-lg align-middle h-full font-sr-sans"
                    >
                      <div
                        class="text-gray-200"
                        v-if="
                          character.skill_trees[idx - 1].max_level <=
                          (idx == 1 ? 6 : 10)
                        "
                      >
                        {{ character.skill_trees[idx - 1].level }}
                        <span class="text-gray-400"
                          >/{{ character.skill_trees[idx - 1].max_level }}</span
                        >
                      </div>
                      <div v-else class="text-cyan-400">
                        {{
                          character.skill_trees[idx - 1].level +
                          (idx == 1 ? 1 : 2)
                        }}
                        <span class="text-gray-400"
                          >/{{ character.skill_trees[idx - 1].max_level }}</span
                        >
                      </div>
                    </div>
                  </div>
                </div>
                <!-- 右侧第四块：遗器 -->
                <MyCarousel
                  v-model="relicIdx"
                  v-if="character.relics && character.relics.length > 0"
                  class="mt-2 w-full h-40 rounded-xl bg-black bg-opacity-20 backdrop-blur-md relative z-20"
                  show-arrow="never"
                  show-indicator="always"
                  :indicator-bg="false"
                  :autoplay="false"
                >
                  <div
                    v-for="relic in character.relics"
                    :key="relic.id"
                    class="pb-2 pr-2 pl-4 w-full flex flex-row h-40 text-gray-200"
                  >
                    <img
                      style="height: 100%; margin-left: -20px"
                      class="artifact-mask w-36 object-cover"
                      :src="apiUrl + relic.icon"
                    />
                    <div class="w-full h-full relative">
                      <div
                        class="text-gray-400 absolute right-0 top-1 flex flex-row"
                      >
                        <div class="truncated">{{ relic.name }}</div>
                        <div
                          :class="{
                            'border-orange-400 bg-orange-900 text-orange-300':
                              relic.rarity == 5,
                            'border-purple-400 bg-purple-900 text-purple-300':
                              relic.rarity == 4,
                            'border-blue-400 bg-blue-900 text-blue-300':
                              relic.rarity == 3,
                            'border-green-400 bg-green-900 text-green-300':
                              relic.rarity == 2,
                          }"
                          class="h-full justify-end ml-2 font-sr-sans rounded-full border px-2"
                        >
                          +{{ relic.level }}
                        </div>
                      </div>
                      <!-- 主词条、等级 -->
                      <div class="text-left mt-7 w-full flex flex-row">
                        <div class="mt-1 flex flex-row">
                          <StatIcon
                            game="sr"
                            :stat="relic.main_affix.field"
                            fill="#d1d5db"
                            class="h-5 w-5 mr-2"
                            style="margin-top: 6px"
                          />
                          <div
                            class="text-gray-200 text-lg truncated"
                            style="max-width: 220px"
                          >
                            {{ relic.main_affix.name }}
                          </div>
                        </div>
                        <div>
                          <span
                            class="text-gray-200 text-3xl ml-2 font-sr-sans"
                            >{{ relic.main_affix.display }}</span
                          >
                        </div>
                      </div>
                      <!-- 副词条 -->
                      <div
                        v-if="relic.sub_affix && relic.sub_affix.length > 0"
                        class="grid grid-cols-2 mt-2 pr-2 grid-rows-2 gap-1 w-full text-left"
                      >
                        <div
                          v-for="substat in relic.sub_affix"
                          :key="substat.type"
                          class="flex flex-row justify-between"
                        >
                          <div class="flex flex-row">
                            <StatIcon
                              game="sr"
                              :stat="substat.field"
                              fill="#ccc"
                              class="h-5 w-5 mr-2"
                              style="margin-top: 4px"
                            />
                            <span
                              class="text-gray-200 font-sr-sans text-xl ml-2"
                              >{{ substat.display }}</span
                            >
                          </div>
                          <div class="flex flex-row mr-5">
                            <div
                              v-for="i in substat.count - 1"
                              :key="i"
                              class="ml-1 mt-0 text-center text-sm"
                            >
                              <img
                                src="../../../assets/statIcons/statEnhance.png"
                                class="h-4 invert opacity-70 mt-1"
                                :style="`transform: translate(calc(${substat.count - i - 1}*5px));`"
                              />
                            </div>
                          </div>
                        </div>
                      </div>
                      <div v-else class="mt-2 text-left text-gray-300 text-lg">
                        {{ $t('sr_noSubstats') }}
                      </div>
                    </div>
                  </div>
                </MyCarousel>
                <div
                  v-else
                  class="mt-2 w-full h-40 rounded-xl pt-16 text-gray-200 text-center align-middle bg-black bg-opacity-20 backdrop-blur-md"
                >
                  {{ $t('sr_noRelics') }}
                </div>
                <div
                  v-if="character.relics && character.relics.length > 0"
                  class="flex flex-row justify-between"
                >
                  <div class="text-gray-900 ml-1 mt-1 flex flex-row">
                    <div
                      class="rounded-full bg-gray-200 font-serif font-bold middle h-6 w-6"
                    >
                      {{ $t('sr_outerSets') }}
                    </div>
                    <pre
                      class="text-gray-100 text-left font-sr ml-2 text-sm"
                      style="margin-top: 2px"
                      >{{ getOuterSets(character.relic_sets) }}</pre
                    >
                  </div>
                  <div class="text-gray-900 mt-1 mr-1 flex flex-row">
                    <pre
                      class="text-gray-100 mr-2 text-right font-sr text-sm"
                      style="margin-top: 2px"
                      >{{ getInnerSet(character.relic_sets) }}</pre
                    >
                    <div
                      class="rounded-full bg-gray-200 font-serif font-bold middle h-6 w-6"
                    >
                      {{ $t('sr_innerSets') }}
                    </div>
                  </div>
                </div>
                <div v-else class="flex flex-row justify-between">
                  <div class="text-gray-900 ml-1 mt-1 flex flex-row">
                    <div
                      class="rounded-full bg-gray-200 font-serif font-bold middle h-6 w-6"
                    >
                      {{ $t('sr_outerSets') }}
                    </div>
                    <div
                      class="text-gray-100 font-sr ml-2 text-sm"
                      style="margin-top: 2px"
                    >
                      {{ $t('sr_noRelicSets') }}
                    </div>
                  </div>
                  <div class="text-gray-900 mt-1 mr-1 font-sr flex flex-row">
                    <div
                      class="text-gray-100 mr-2 text-sm"
                      style="margin-top: 2px"
                    >
                      {{ $t('sr_noRelicSets') }}
                    </div>
                    <div
                      class="rounded-full bg-gray-200 font-serif font-bold middle h-6 w-6"
                    >
                      {{ $t('sr_innerSets') }}
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </MyCarousel>
    </div>
    <div
      v-else
      class="pt-2 pb-4"
      :style="`font-size: calc(max(14px * min(${hScale}, ${vScale}), 16px))`"
    >
      {{ $t('gs_emptyPlayerTip') }}
    </div>
  </div>
</template>

<style lang="scss" scoped>
.font-sr {
  font-family: sr-font, sans-serif;
}

.font-sr-sans {
  font-family: sr-sans-font, sans-serif;
}

.loading {
  @apply translate-y-[300px] opacity-0;
}

.char-side-icon {
  -webkit-mask: radial-gradient(white 80%, transparent);
}

.gacha-mask {
  -webkit-mask: linear-gradient(transparent 1rem, white 3rem);
}

.left-gacha {
  -webkit-mask: linear-gradient(270deg, transparent, white 20%);
}

.artifact-mask {
  -webkit-mask: linear-gradient(270deg, transparent, white 60%);
}

.disabled {
  @apply bg-gray-200 opacity-30 pointer-events-none;

  .dark & {
    @apply bg-gray-600 opacity-40;
  }
}

.truncated {
  @apply inline-block max-w-full overflow-ellipsis whitespace-nowrap overflow-hidden;
}
</style>
